package com.cx.mall.search.service.impl;

import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch._types.query_dsl.RangeQuery;
import co.elastic.clients.json.JsonData;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cx.mall.common.model.goods.Product;
import com.cx.mall.common.model.search.SkuEs;
import com.cx.mall.search.handler.HighlightQueryHandler;
import com.cx.mall.search.service.IProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.annotations.Highlight;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.client.elc.NativeQuery;
import org.springframework.data.elasticsearch.client.elc.NativeQueryBuilder;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.HighlightQuery;
import org.springframework.stereotype.Service;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class ProductServiceImpl implements IProductService {
    @Autowired
    private ElasticsearchTemplate esTemplate;
    @Override
    public IPage page(Product product) {
        // 1 构建查询条件
        NativeQueryBuilder builder = NativeQuery.builder();
        // 2 执行查询，由于条件比较复杂，所以使用分段构建
        List<Query> queryList = new ArrayList<>();
        // 2.1 按关键字查询（商品名称）
        boolQuery(queryList,"sku_name",product.getSkuName());
        // 2.2 按品牌查询
        boolQuery(queryList,"brand_id",product.getBrandId());
        // 2.3 按分类查询( 只有三级类别）(在openfeign中做一个按照父类查子类的方法，在这里调用接口）
        boolQuery(queryList,"category_id",product.getCategoryId());
        // 2.4 按价格区间查询
        rangeQuery(queryList,"price",product.getRange());
        // 2.5 按照上架日期查询最新的在最前面
        sortQuery(builder);
        // 3 执行查询
        // 3.1 构建分页

        if (product.getCurrent() != null && product.getSize() != null) {
            builder = builder.withPageable(
                    PageRequest.of(product.getCurrent() - 1,
                            product.getSize()));
        }else {
            builder = builder.withPageable(PageRequest.of(0, 10));
            product.setSize(10);
            product.setCurrent(1);
        }
        // 3.2 构建查询条件
        builder = builder
                .withQuery(bool -> bool.bool(m -> m.must(queryList)))
                // 设置筛选字段
                .withSourceFilter(new FetchSourceFilter(new String[]{"id","spu_id","sku_name", "sku_default_img", "price","create_time"},null));
        // 3.3 构建高亮显示
        builder = builder.withHighlightQuery(highlightQuery("sku_name"));
        // 执行查询
        SearchHits<SkuEs> hits = esTemplate.search(builder.build(), SkuEs.class);
        // 4 结果解析
        // 高亮查询字段替换
        List<SkuEs> skuEsList = HighlightQueryHandler.parseHighlightResult(hits,SkuEs.class,"skuName");
        /*List<SkuEs> skuEsList = hits.getSearchHits().stream()
                .map(SearchHit::getContent)
                .collect(Collectors.toList());*/

        IPage<SkuEs> page = new Page<>(product.getCurrent(),product.getSize());
        page.setTotal(hits.getTotalHits());
        page.setRecords(skuEsList);
        return page;
    }

    /**
     * 按组合条件查询
     * @param queryList
     * @param field
     * @param value
     */
    private void boolQuery(List<Query> queryList,String field,Object value){
        if (value != null) {
            Query query = Query.of(builder ->
                    builder.match(match ->
                            match.field(field).query(value.toString())
                    )
            );
            queryList.add(query);
        }
    }

    /**
     * 按区间查询
     * @param queryList
     * @param field
     * @param range
     */
    private void rangeQuery (List<Query> queryList,String field,String range){
        if (range != null) {
            String[] prices = range.split("-"); // 范围：0-1000， 1000-2000
            // 构建查询条件
            RangeQuery rangeQuery;
            if(prices.length == 2){
                rangeQuery = RangeQuery.of(r->r
                        .field(field)
                        .gt(JsonData.of(prices[0]))
                        .lte(JsonData.of(prices[1])));

            }else {
                rangeQuery = RangeQuery.of(r->r
                        .field(field)
                        .gt(JsonData.of(prices[0])));
            }
            Query query = Query.of(builder -> builder.range(rangeQuery));
            queryList.add(query);
        }
    }

    /**
     * 高亮查询
     * @param field
     * @return
     */
    public HighlightQuery highlightQuery(String field) {
        // 分解方法名
        String[] split = field.split("_");
        String methodName = split[0] +  split[1].substring(0,1).toUpperCase() + split[1].substring(1);
        // 获取方法和注解
        Class clazz = HighlightQueryHandler.class;
        try {
            // 获取方法
            Method method = clazz.getDeclaredMethod(methodName);
            if (method != null) {
                // 获取注解
                Highlight highlight = method.getAnnotation(Highlight.class);
                // 创建高亮查询
                HighlightQuery query = new HighlightQuery(
                        org.springframework.data.elasticsearch.core.query.highlight.Highlight.of(highlight),
                        SkuEs.class);
                return query;
            }
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    /**
     * 按照上架时间排序
     * 新品在前
     */
    public void sortQuery(NativeQueryBuilder builder) {
        // 按上架时间降序排序（最新上架的排在前面）
        builder.withSort(sort -> sort
                .field(field -> field
                        .field("create_time")  // 假设上架时间字段名为create_time
                        .order(co.elastic.clients.elasticsearch._types.SortOrder.Desc)  // 降序排列
                )
        );
    }
}
